package cn.elead.chaos.framework.util;

import java.util.List;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;

import cn.elead.chaos.core.util.TypeUtils;
import cn.elead.chaos.framework.web.global.ApiResponse;
import cn.elead.chaos.framework.web.global.ErrorCode;
import cn.elead.chaos.framework.web.global.ErrorCodeEnum;
import cn.elead.chaos.framework.web.global.FailedResponse.FailedResponseBuilder;
import cn.elead.chaos.framework.web.wrapper.ResponseWrapper;

import cn.hutool.core.util.ObjectUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * response输出工具类
 *
 * @author luopeng
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class ResponseUtils {

	/**
	 * Portal输出json字符串
	 *
	 * @param response
	 * @param obj      需要转换JSON的对象
	 */
	public static void writeValAsJson(HttpServletRequest request, ResponseWrapper response, Object obj) {
		if (ObjectUtil.isNotNull(response) && ObjectUtil.isNotNull(obj)) {
			response.writeValueAsJson(obj);
		}
	}

	/**
	 * 打印日志信息但是不输出到浏览器
	 *
	 * @param request
	 * @param obj
	 */
	public static void writeValAsJson(HttpServletRequest request, Object obj) {
		writeValAsJson(request, null, obj);
	}

	/**
	 * 发送错误信息
	 *
	 * @param request
	 * @param response
	 * @param code
	 */
	public static void sendFail(HttpServletRequest request, HttpServletResponse response, ErrorCode code, Exception exception) {
		if (ObjectUtil.isNotNull(request) && ObjectUtil.isNotNull(code)) {
			code.setPath(request.getRequestURI());
		}
		ResponseUtils.writeValAsJson(request, getWrapper(response, code), ApiResponse.failure(code, exception));
	}

	/**
	 * 发送错误信息
	 *
	 * @param request
	 * @param response
	 * @param code
	 */
	public static void sendFail(HttpServletRequest request, HttpServletResponse response, ErrorCode code) {
		sendFail(request, response, code, null);
	}

	/**
	 * 发送错误信息
	 *
	 * @param request
	 * @param response
	 * @param codeEnum
	 */
	public static void sendFail(HttpServletRequest request, HttpServletResponse response, ErrorCodeEnum codeEnum) {
		sendFail(request, response, codeEnum.convert(), null);
	}

	/**
	 * 发送错误信息
	 *
	 * @param request
	 * @param response
	 * @param codeEnum
	 * @param exception
	 */
	public static void sendFail(HttpServletRequest request, HttpServletResponse response, ErrorCodeEnum codeEnum, Exception exception) {
		sendFail(request, response, codeEnum.convert(), exception);
	}

	/**
	 * 获取Response
	 *
	 * @return
	 */
	public static ResponseWrapper getWrapper(HttpServletResponse response, ErrorCode errorCode) {
		return new ResponseWrapper(response, errorCode);
	}

	/**
	 * 获取异常信息
	 *
	 * @param exception
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static FailedResponseBuilder exceptionMsg(FailedResponseBuilder failedResponseBuilder, Exception exception) {
		if (exception instanceof MethodArgumentNotValidException) {
			StringBuilder builder = new StringBuilder("校验失败:");
			List<ObjectError> allErrors = ((MethodArgumentNotValidException) exception).getBindingResult().getAllErrors();
			allErrors.stream().findFirst().ifPresent(error -> {
				builder.append(((FieldError) error).getField()).append("字段规则为").append(error.getDefaultMessage());
				failedResponseBuilder.exception(error.getDefaultMessage());
			});
			failedResponseBuilder.msg(builder.toString());
			return failedResponseBuilder;
		} else if (exception instanceof MissingServletRequestParameterException) {
			StringBuilder builder = new StringBuilder("参数字段");
			MissingServletRequestParameterException ex = (MissingServletRequestParameterException) exception;
			builder.append(ex.getParameterName());
			builder.append("校验不通过");
			failedResponseBuilder.msg(builder.toString()).exception(ex.getMessage());
			return failedResponseBuilder;
		} else if (exception instanceof MissingPathVariableException) {
			StringBuilder builder = new StringBuilder("路径字段");
			MissingPathVariableException ex = (MissingPathVariableException) exception;
			builder.append(ex.getVariableName());
			builder.append("校验不通过");
			failedResponseBuilder.msg(builder.toString()).exception(ex.getMessage());
			return failedResponseBuilder;
		} else if (exception instanceof ConstraintViolationException) {
			StringBuilder builder = new StringBuilder("方法.参数字段");
			ConstraintViolationException ex = (ConstraintViolationException) exception;
			Optional<ConstraintViolation<?>> first = ex.getConstraintViolations().stream().findFirst();
			if (first.isPresent()) {
				ConstraintViolation<?> constraintViolation = first.get();
				builder.append(constraintViolation.getPropertyPath().toString());
				builder.append("校验不通过");
				failedResponseBuilder.msg(builder.toString()).exception(constraintViolation.getMessage());
			}
			return failedResponseBuilder;
		}

		failedResponseBuilder.exception(TypeUtils.castToString(exception));
		return failedResponseBuilder;
	}
}
